package com.one.group.admin.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.one.group.admin.dao.impl.ChargeInfoDaoImpl;
import com.one.group.admin.mapper.*;
import com.one.group.model.dto.*;
import com.one.group.model.entity.*;
import com.one.group.model.vo.SpBillQueryVo;
import com.one.group.service.SpBillService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
public class SpBillServiceImpl extends ServiceImpl<SpBillMapper, SpBill> implements SpBillService {
    @Autowired
    private OwnerMapper spOwnerMapper;
    @Autowired
    private SpRenterMapper spRenterMapper;
    @Autowired
    private SpCustomerMapper spCustomerMapper;
    @Autowired
    private SpChargeStandardsMapper spChargeStandardsMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ChargeInfoDaoImpl chargeInfoDao;
    /**
     * 添加账单
     * @param payerType 缴费人类型(1:业主 2:租房人员 3:客户)
     * @param payerId 缴费人id
     * @param chargestandardId 收费标准id
     * @param Amount 缴费金额
     * @param remark 账单备注
     * @return true:添加成功 false:添加失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean myAdd(Integer payerType,Long payerId, Long chargestandardId, BigDecimal Amount, String remark) {
        try {
            //获取到缴费人信息
            HashMap<String, Object> payerInfo = getPayerInfo(payerType, payerId);
            //获取收费标准信息
            SpChargeStandards spChargeStandards = spChargeStandardsMapper.mySelectOneById(chargestandardId);
            //创建账单
            SpBill spBill = new SpBill();
            spBill.setNumber(generateBillNumber());
            spBill.setCellId(spChargeStandards.getCellId());
            spBill.setPayer((String) payerInfo.get("payerName"));
            spBill.setPayer_id((Long) payerInfo.get("payerId"));
            spBill.setPayer_type(payerType);
            spBill.setPhone((String) payerInfo.get("payerPhone"));
            spBill.setEmail((String) payerInfo.get("payerEmail"));
            spBill.setChargestandardId(chargestandardId);
            spBill.setReceivableAmount(Amount);
            spBill.setTotalAmount(Amount);
            spBill.setTimeset(spChargeStandards.getTimeset());
            spBill.setBillNature(spChargeStandards.getTimeset()==0?0:1);
            spBill.setStatus(0);
            spBill.setRemark(remark==null?spChargeStandards.getRemarks():remark);
            spBill.setTenantId(spChargeStandards.getTenantId());
            return getMapper().billAdd(spBill);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<SpBillQueryVo> myQueryList(SpBillQueryDto spBillQueryDto,Integer status) {
        //获取租户id
        Long tenant_id = Convert.toLong(StpUtil.getExtra("tenant_id"));
        return getMapper().myQueryList(spBillQueryDto.getName(),spBillQueryDto.getNotification(),status,tenant_id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean sendNotification(BaseDeleteDto baseDeleteDto) {
        try{
            List<Long> ids = baseDeleteDto.getIds();
            for (Long id : ids) {
                SpSendEmailDto spSendEmailDto = new SpSendEmailDto();
                //获取账单信息
                SpBill spBill = getMapper().selectOneById(id);
                SpChargeStandards spChargeStandards = spChargeStandardsMapper.mySelectOneById(spBill.getChargestandardId());
                spSendEmailDto.setEmail(spBill.getEmail());
                String message = "";
                if(spBill.getBillNature()==0){
                    message = "<h2>智慧物业平台</h2>\n"
                            + "<p>" + spBill.getPayer() + "先生您好：</p>\n"
                            + "<p>您于" + DateUtil.formatDateTime(spBill.getCreate_time())+ "产生的有关" + spChargeStandards.getName() + "收费项目的账单，金额为：" + spBill.getTotalAmount() + "，请及时缴费！否则将产生征信影响。</p>";

                }else {
                    message = "<h2>智慧物业平台</h2>\n"
                            + "<p>" + spBill.getPayer() + "先生您好：</p>\n"
                            + "<p>您于" + DateUtil.formatDateTime(spBill.getCreate_time()) + "产生的有关" + spChargeStandards.getName() + "收费项目的账单，金额为：" + spBill.getTotalAmount() + "，请及时缴费！</p>\n"
                            + "<p>请于" + DateUtil.formatDateTime(getDueDays(spBill.getCreate_time(), spChargeStandards.getTimeset())) + "之前完成缴费，否则将产生逾期费用。</p>";
                }
                spSendEmailDto.setContent(message);
                rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
                rabbitTemplate.convertAndSend("gxa.direct","sendEmail",spSendEmailDto);
                spBill.setNotification(1);
                if(!updateById(spBill)){
                    throw new RuntimeException("通知信息更新失败");
                }
            }
            return true;
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object Payerlist(PayerlistDto payerlistDto) {
        return getMapper().Payerlist(payerlistDto.getName());
    }

    @Override
    public List<SpBillQueryVo> myPayerBillQuery(PayerBillQueryDto payerBillQueryDto, Integer i) {
        //获取租户id
        Long tenant_id = Convert.toLong(StpUtil.getExtra("tenant_id"));
        return getMapper().myPayerBillQuery(payerBillQueryDto.getPayerId(),payerBillQueryDto.getPayerType(),i,tenant_id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean BillPay(PayerBillDto payerBillDto) {
        try{
            if(payerBillDto.getPayType()!=1){
                for (Long id : payerBillDto.getIds()){
                    SpBill spBill = getMapper().selectOneById(id);
                    spBill.setPaymentype(2);
                    spBill.setStatus(1);
                    if(!updateById(spBill)){
                        throw new RuntimeException("账单更新失败");
                    }
                    ChargeInfo chargeInfo = getMapper().queryChargeInfo(id);
                    rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
                    rabbitTemplate.convertAndSend("gxa.direct","recordChargeInfoDto",chargeInfo);
                }
                return true;
            }else {
                for (Long id : payerBillDto.getIds()){
                    SpBill spBill = getMapper().selectOneById(id);
                    spBill.setPaymentype(1);
                    spBill.setStatus(1);
                    if(!updateById(spBill)){
                        throw new RuntimeException("账单更新失败");
                    }
                }
                SpBill spBill = getMapper().selectOneById(payerBillDto.getIds().get(0));
                if(getMapper().payBillByPrepaid(spBill.getPayer_id(),spBill.getPayer_type(),payerBillDto.getAmount(),spBill.getTenantId())){
                    ChargeInfo chargeInfo = getMapper().queryChargeInfo(payerBillDto.getIds().get(0));
                    rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
                    rabbitTemplate.convertAndSend("gxa.direct","recordChargeInfoDto",chargeInfo);
                    return true;
                }else throw new RuntimeException("预存账单支付失败");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
    @Override
    public BigDecimal paiedTotalAmount() {
        Double totalAmount = chargeInfoDao.getTotalAmount();
        return BigDecimal.valueOf(totalAmount);
    }

    private HashMap<String,Object> getPayerInfo(Integer payerType,Long payerId){
        HashMap<String,Object> payerInfo = new HashMap<>();
        switch (payerType){
            case 1: {
                //属于业主表的数据
                Owner spOwner = spOwnerMapper.mySelectOneById(payerId);
                payerInfo.put("payerId",payerId);
                payerInfo.put("payerName",spOwner.getName());
                payerInfo.put("payerPhone",spOwner.getPhone());
                payerInfo.put("payerEmail",spOwner.getEmail());
            }
                break;
            case 2: {
                //属于租户(租房人员)表的数据
                SpRenter spRenter = spRenterMapper.mySelectOneById(payerId);
                payerInfo.put("payerId",payerId);
                payerInfo.put("payerName",spRenter.getName());
                payerInfo.put("payerPhone",spRenter.getPhone());
                payerInfo.put("payerEmail",spRenter.getEmail());
            }
                break;
            case 3: {
                //属于客户表的数据
                SpCustomer spCustomer = spCustomerMapper.mySelectOneById(payerId);
                payerInfo.put("payerId",payerId);
                payerInfo.put("payerName",spCustomer.getName());
                payerInfo.put("payerPhone",spCustomer.getPhone());
                payerInfo.put("payerEmail",spCustomer.getEmail());
            }
                break;
            default:   throw new RuntimeException("缴费人类型错误");
        }
        return payerInfo;
    }
    //账单编号生成器
    private String generateBillNumber(){
        return "B" + System.currentTimeMillis();
    }
    @Transactional(rollbackFor = Exception.class)
    public Boolean BillAdd(SpBillAddTestDto spBillAddTestDto){
        return myAdd(spBillAddTestDto.getPayerType(),spBillAddTestDto.getPayerId(),spBillAddTestDto.getChargestandardId(),spBillAddTestDto.getAmount(),spBillAddTestDto.getRemark());
    }
    private Date getDueDays(Date updated_time, Integer timeset){
        return switch (timeset) {
            case 1 -> DateUtil.offsetHour(updated_time, 1);
            case 2 -> DateUtil.offsetDay(updated_time, 1);
            case 3 -> DateUtil.offsetDay(updated_time, 7);
            case 4 -> DateUtil.offsetMonth(updated_time, 1);
            case 5 -> DateUtil.offsetYear(updated_time, 1);
            default -> throw new RuntimeException("时间段错误");
        };
    }
}
